package com.mine.frame.mylandemo.service

import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import android.util.Log
import com.mine.frame.mylandemo.service.mthrowable.InputStreamThrowable
import com.mine.frame.mylandemo.service.mthrowable.OutputStreamThrowable
import com.mine.frame.mylandemo.service.mthrowable.SocketDisconnectThrowable
import com.swallowsonny.convertextlibrary.toHexString
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.disposables.Disposable
import io.reactivex.rxjava3.functions.Consumer
import io.reactivex.rxjava3.schedulers.Schedulers
import java.io.BufferedReader
import java.io.InputStream
import java.io.InputStreamReader
import java.io.OutputStream
import java.net.ConnectException
import java.net.InetSocketAddress
import java.net.Socket
import java.nio.charset.Charset
import java.util.*


/**
 * company 广东玛格家居有限公司
 * @author smoker
 * @Date 2021/12/17
 * Description:Service
 */
class MineConnectService : Service() {
    companion object {
        private const val TAG = "MineConnectService"
    }

    private var ip = ""
    private var port = 0

    private lateinit var mBinder: MineConnectServiceBinder

    private var mSocket: Socket? = null
    private var connectDisposable: Disposable? = null

    private var outputStream: OutputStream? = null
    private var outputDisposable: Disposable? = null

    private var inputStream: InputStream? = null
    private var inputDisposable: Disposable? = null

    private var connectStateListener: ((SocketState) -> Unit?)? = null

    private var readInfoListener: ((ByteArray) -> Unit)? = null

    inner class MineConnectServiceBinder : Binder() {
        fun getService(): MineConnectService = this@MineConnectService
    }

    override fun onCreate() {
        super.onCreate()
        if (!this::mBinder.isInitialized) {
            mBinder = MineConnectServiceBinder()
        }
        updateState(SocketState.SocketDisConnect)

    }

    override fun onBind(intent: Intent?): IBinder = mBinder


    override fun onUnbind(intent: Intent?): Boolean {
        closeSocket()
        return super.onUnbind(intent)
    }

    fun addConnectStateListener(listener: (state: SocketState) -> Unit) {
        this.connectStateListener = listener
    }

    fun addReadInfoListener(listener: (info: ByteArray) -> Unit) {
        this.readInfoListener = listener
    }


    /**
     * 开始连接
     */
    fun connect(ip: String, port: Int) {
        if (this.ip == ip && this.port == port) {
            if (null != connectDisposable && null != mSocket && mSocket?.isConnected == true) {
                updateState(SocketState.SocketConnectSuccess)
                return
            } else {
                closeSocket()
                onConnectSocketServer(ip, port)
            }
        } else {
            closeSocket()
            onConnectSocketServer(ip, port)
        }
        this.ip = ip
        this.port = port
    }

    /**
     * 断开连接
     */
    fun disconnect() {
        closeSocket()
    }


    /**
     * 发送消息
     */
    fun sent(info: String) {
        if (outputDisposable != null || outputDisposable?.isDisposed == false) {
            updateState(SocketState.SocketWriting)
            return
        }
        if (null == mSocket || mSocket?.isClosed == true) {
            updateState(SocketState.SocketDisConnect)
            return
        }
        onCreateWriteManager(info)
    }


    /**
     * 发送消息
     */
    fun sent(info: ByteArray) {
        if (outputDisposable != null || outputDisposable?.isDisposed == false) {
            updateState(SocketState.SocketWriting)
            return
        }
        if (null == mSocket || mSocket?.isClosed == true) {
            updateState(SocketState.SocketDisConnect)
            return
        }
        onCreateWriteManager(info)
    }


    /**
     * 开启消息读取
     */
    private fun openRead() {
        if (inputDisposable != null || inputDisposable?.isDisposed == false) {
            updateState(SocketState.SocketReading)
            return
        }
        onCreateReadManager()
    }


    /**
     * 连接Socket
     */
    private fun onConnectSocketServer(ip: String, port: Int) {
        Observable.create<SocketState> {
            it.onNext(SocketState.SocketConnecting)
            log("正在链接: ${ip}:${port}")
            val socket = Socket()
            socket.connect(InetSocketAddress(ip, port), 10000)
            if (socket.isConnected) {
                mSocket = socket
                it.onNext(SocketState.SocketConnectSuccess)
            }
            it.onComplete()
        }
            .subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread())
            .onErrorReturn {
                if (it is ConnectException) {
                    it.printStackTrace()
                    SocketState.SocketAddressInvalid
                } else {
                    SocketState.SocketDisConnect
                }
            }
            .doOnSubscribe {
                this.connectDisposable = it
            }
            .doOnNext { state ->
                updateState(state)
                if (state == SocketState.SocketConnectSuccess) {
                    log("开启读取通道")
                    openRead()
                }
            }
            .doOnError {
                it?.printStackTrace()
                updateState(SocketState.SocketDisConnect)
            }.subscribe()
    }

    /**
     * 创建写入流
     */
    private fun onCreateWriteManager(send: String) {
        this.outputDisposable = Observable.just(send)
            .flatMap {
                if (it.isNullOrEmpty()) {
                    throw Throwable("发送内容不能为空")
                } else {
                    log("sentInfo(String):${it}")
                    val info = it.toByteArray(Charset.defaultCharset())
                    log("sentInfo(byte):${info.contentToString()}")
                    Observable.just(info)
                }
            }
            .flatMap { info ->
                mSocket?.let { socket ->
                    outputStream ?: let {
                        outputStream = socket.getOutputStream()
                        Observable.just(SocketState.SocketOutputStreamOpen)
                    }
                    outputStream?.let { out ->
                        out.write(info)
                        out.flush()
                        Observable.just(SocketState.SocketWriteSuccess)
                    } ?: let {
                        throw OutputStreamThrowable("OutputStream:已断开连接")
                    }
                } ?: let {
                    throw SocketDisconnectThrowable("Socket:已断开连接")
                }
            }
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .doOnComplete {
                closeOutputDisposable()
            }
            .subscribe({ updateState(it) },
                {
                    it.printStackTrace()
                    when (it) {
                        is SocketDisconnectThrowable -> {
                            updateState(SocketState.SocketDisConnect)
                        }
                        is OutputStreamThrowable -> {
                            updateState(SocketState.SocketWriteError)
                        }
                        else -> {
                            updateState(SocketState.SocketWriteError)
                        }
                    }
                    closeOutputDisposable()
                })

    }


    /**
     * 创建写入流
     * byteArray
     */
    private fun onCreateWriteManager(send: ByteArray) {
        this.outputDisposable = Observable.just(send)
            .flatMap { info ->
                mSocket?.let { socket ->
                    outputStream ?: let {
                        outputStream = socket.getOutputStream()
                        Observable.just(SocketState.SocketOutputStreamOpen)
                    }
                    outputStream?.let { out ->
                        log("sent(Hex):${info.toHexString()}")
                        out.write(info)
                        out.flush()
                        Observable.just(SocketState.SocketWriteSuccess)
                    } ?: let {
                        throw OutputStreamThrowable("OutputStream:已断开连接")
                    }
                } ?: let {
                    throw SocketDisconnectThrowable("Socket:已断开连接")
                }
            }
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .doOnComplete {
                closeOutputDisposable()
            }
            .subscribe({ updateState(it) },
                {
                    it.printStackTrace()
                    when (it) {
                        is SocketDisconnectThrowable -> {
                            updateState(SocketState.SocketDisConnect)
                        }
                        is OutputStreamThrowable -> {
                            updateState(SocketState.SocketWriteError)
                        }
                        else -> {
                            updateState(SocketState.SocketWriteError)
                        }
                    }
                    closeOutputDisposable()
                })

    }

    /**
     * 创建读取流
     */
    private fun onCreateReadManager() {
        this.inputDisposable = Observable.create<Any> { emitter ->
            mSocket?.let { socket ->
                inputStream ?: let {
                    inputStream = socket.getInputStream()
                    emitter.onNext(SocketState.SocketInputStreamOpen)
                }
                inputStream?.let { input ->
                    val read = ByteArray(1024)
                    var len: Int
                    while ((input.read(read)).also { len = it } != -1) {
                        val result = ByteArray(len)
                        System.arraycopy(read ,0 ,result ,0 ,len)
                        emitter.onNext(SocketState.SocketReadSuccess)
                        emitter.onNext(result)
                    }
                } ?: let {
                    throw InputStreamThrowable("InputStream:已断开连接")
                }

            } ?: let {
                throw SocketDisconnectThrowable("Socket:已断开连接")
            }

        }.subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .doOnComplete {
                log("onCreateReadManager : 消息接收完成")
            }
            .subscribe({ result ->
                when (result) {
                    is SocketState -> {
                        updateState(result)
                    }
                    is ByteArray ->{
                        readInfoListener?.let { listener ->
                            listener(result)
                        }
                    }
                    else -> {
                        readInfoListener?.let { listener ->
                            listener(result.toString().toByteArray())
                        }
                    }
                }
            }, {
                it.printStackTrace()
                when (it) {
                    is SocketDisconnectThrowable -> {
                        updateState(SocketState.SocketDisConnect)
                    }
                    is InputStreamThrowable -> {
                        updateState(SocketState.SocketReadError)
                    }
                    else -> {
                        updateState(SocketState.SocketReadError)
                    }
                }
            })
    }

    /**
     * 关闭Socket
     */
    private fun closeSocket() {
        closeInput()
        closeOutput()
        log("执行关闭Socket操作")
        mSocket?.let {
            if (!it.isClosed) {
                it.close()
            }
        }
        mSocket = null
        connectDisposable?.let {
            if (!it.isDisposed) {
                it.dispose()
            }
        }
        connectDisposable = null
        updateState(SocketState.SocketDisConnect)

    }

    /**
     * 关闭输出流
     */
    private fun closeOutput() {
        log("执行关闭OutputStream操作")
        mSocket?.let {
            if (!it.isClosed) {
                it.shutdownOutput()
            }
        }
        outputStream?.close()
        outputStream = null
        closeOutputDisposable()
        updateState(SocketState.SocketOutputStreamClose)
    }

    /**
     * 关闭输入流
     */
    private fun closeInput() {
        log("执行关闭InputStream操作")
        mSocket?.let {
            if (!it.isClosed) {
                it.shutdownInput()
            }
        }
        inputStream?.close()
        inputStream = null
        //closeInputDisposable()
        updateState(SocketState.SocketInputStreamClose)
    }

    /**
     * 关闭输出流的Disposable
     */
    private fun closeOutputDisposable() {
        outputDisposable?.let {
            if (!it.isDisposed) {
                it.dispose()
            }
        }
        outputDisposable = null
    }

    /**
     * 关闭输入流的Disposable
     */
    private fun closeInputDisposable() {
        inputDisposable?.let {
            if (!it.isDisposed) {
                it.dispose()
            }
        }
        inputDisposable = null
    }


    /**
     * 更新当前socket的状态
     */
    private fun updateState(state: SocketState) {
        connectStateListener?.let { it(state) }
    }

    private fun log(info: CharSequence) {
        Log.e(TAG, info as String)
    }
}